package com.smedi.ismedi.constructionproject.core.application.query.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.smedi.ismedi.constructionproject.core.application.command.ProjectAssignmentListQueryCommand;
import com.smedi.ismedi.constructionproject.core.application.query.ProjectAssignmentQueryService;
import com.smedi.ismedi.constructionproject.core.application.query.ProjectBasicQueryService;
import com.smedi.ismedi.constructionproject.core.application.query.vo.ProjectAssignmentVo;
import com.smedi.ismedi.constructionproject.core.application.query.vo.ProjectBasicVo;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.ProjectAssignment;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.ProjectAssignmentForMobile;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.ProjectBasic;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.dto.ProjectAssignmentQuery;
import com.smedi.ismedi.constructionproject.core.domain.repository.ProjectAssignmentRepository;
import com.smedi.ismedi.constructionproject.core.domain.repository.ProjectBasicRepository;
import com.smedi.ismedi.constructionproject.core.infrastructure.constant.CustomError;
import com.smedi.ismedi.constructionproject.core.port.adapter.persistence.mybatis.mapper.ProjectAssignmentMapper;
import com.smedi.ismedi.constructionproject.core.port.adapter.service.AuthorityAccessRemoteApiService;
import com.smedi.ismedi.constructionproject.core.port.adapter.service.InmallRemoteApiService;
import com.smedi.ismedi.constructionproject.core.port.adapter.service.OrganizationRemoteApiService;
import com.smedi.ismedi.constructionproject.core.port.adapter.service.PersonnelRemoteApiService;
import com.smedi.ismedi.organization.api.dto.response.ProjectOrganizationResponse;
import com.smedi.ismedi.personnel.api.dto.response.PersonSimpleResponse;
import com.smedi.ismedi.web.starter.exception.LogicException;
import com.smedi.ismedi.web.starter.util.DozerUtil;
import com.smedi.ismedi.web.starter.util.SegmentateUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: xulinjun
 * @Date: 2021-6-27 12:11
 */
@Slf4j
@Service
@AllArgsConstructor
public class ProjectAssignmentQueryServiceImpl implements ProjectAssignmentQueryService {
    private final PersonnelRemoteApiService personnelRemoteApiService;

    private final OrganizationRemoteApiService organizationRemoteApiService;

    private final SegmentateUtil segmentateUtil;

    private final ProjectAssignmentMapper projectAssignmentMapper;

    private final ProjectAssignmentRepository projectAssignmentRepository;
    private final ProjectBasicRepository projectBasicRepository;

    private final DozerUtil dozerUtil;

    private final ProjectBasicQueryService projectBasicQueryService;

    private final AuthorityAccessRemoteApiService authorityAccessRemoteApiService;

    private final InmallRemoteApiService inmallRemoteApiService;

    /**
     * 装配其他服务的数据
     *
     * @param projectAssignmentVos
     * @return
     */
    private void assembleRemoteInfo(List<ProjectAssignmentVo> projectAssignmentVos) {
        List<Long> personIds = new ArrayList<>();
        List<Long> projectOrganizationIds = new ArrayList<>();
        projectAssignmentVos.stream().forEach(vo -> {
            if (vo.getPersonId() != null) {
                personIds.add(vo.getPersonId());
            }
            if (vo.getProjectOrganizationId() != null) {
                projectOrganizationIds.add(vo.getProjectOrganizationId());
            }
        });

        // 人员信息
        List<PersonSimpleResponse> personSimpleResponses = new ArrayList<>();
        if (personIds.size() > 0) {
            personSimpleResponses = personnelRemoteApiService.getPersonSimpleInfoByPersonIds(personIds);
        }

        // 组织信息
        List<ProjectOrganizationResponse> projectOrganizationResponses = new ArrayList<>();
        if (projectOrganizationIds.size() > 0) {
            projectOrganizationResponses = organizationRemoteApiService.getProjectOrganizationByProjectOrganizationIds(projectOrganizationIds);
        }

        // 装配信息
        List<PersonSimpleResponse> finalPersonSimpleResponses = personSimpleResponses;
        List<ProjectOrganizationResponse> finalProjectOrganizationResponses = projectOrganizationResponses;
        projectAssignmentVos.stream().forEach(vo -> {
            // 人员信息
            Optional<PersonSimpleResponse> personResult = finalPersonSimpleResponses.stream().filter(person -> person.getPersonId().equals(vo.getPersonId())).findFirst();
            if (personResult.isPresent()) {
                vo.setMobile(personResult.get().getMobile())
                        .setLastName(personResult.get().getLastName())
                        .setUserName(personResult.get().getUserName())
                        .setEmployeeNum(personResult.get().getEmployeeNum())
                        .setPersonType(personResult.get().getPersonType())
                        .setPersonTypeMeaning(personResult.get().getPersonTypeMeaning())
                        .setInternal(personResult.get().isInternal())
                        .setEmail(personResult.get().getEmail())
                        .setHasDing(true)
                        .setRoleName(authorityAccessRemoteApiService.queryRoleNameByPersonId(personResult.get().getPersonId()));

            }
            // 组织信息
            Optional<ProjectOrganizationResponse> projectOrganizationResult = finalProjectOrganizationResponses.stream().filter(projectOrganization -> projectOrganization.getProjectOrganizationId().equals(vo.getProjectOrganizationId())).findFirst();
            if (projectOrganizationResult.isPresent()) {
                vo.setProjectOrganizationName(projectOrganizationResult.get().getFullName())
                        .setProjectOrganizationShortName(projectOrganizationResult.get().getShortName());
            }
        });
    }

    @Override
    public IPage getProjectAssignmentPagination(Long offset, Long pageSize, Long projectId, Long projectOrganizationId, String lastName, String userName, String employeeNum, String mobile) {
        Page<ProjectAssignmentVo> page = new Page<>(offset, pageSize);
        page.addOrder(OrderItem.desc("project_assignment_id"));

        IPage<ProjectAssignmentVo> pagination;
        if (StringUtils.isEmpty(lastName) && StringUtils.isEmpty(userName) && StringUtils.isEmpty(mobile) && StringUtils.isEmpty(employeeNum)) {
            pagination = projectAssignmentMapper.selectPaginationByProjectIdAndProjectOrganizationId(page, projectId, projectOrganizationId);
        } else {
            List<Long> personIds = personnelRemoteApiService.getPersonIdsByLastNameAndUserNameAndEmployeeNumAndMobile(lastName, userName, employeeNum, mobile);
            List<List<Long>> segPersonIds = segmentateUtil.doCut(personIds, 999);
            pagination = projectAssignmentMapper.selectPaginationWithPersonIds(page, projectId, projectOrganizationId, segPersonIds);
        }

        assembleRemoteInfo(pagination.getRecords());
        return pagination;
    }

    @Override
    public IPage getProjectAssignmentPaginationContainsChildren(Long offset, Long pageSize, Long projectId, Long projectOrganizationId, String lastName, String userName, String employeeNum, String mobile) {
        Page<ProjectAssignmentVo> page = new Page<>(offset, pageSize);
        page.addOrder(OrderItem.desc("project_assignment_id"));

        if (projectOrganizationId == null) {
            throw LogicException.raise(CustomError.PROJECT_ORGANIZATION_ID_MISS);
        }

        List<Long> projectOrganizationIds = organizationRemoteApiService.getProjectOrganizationChildrenOrgIdList(projectOrganizationId);
        List<List<Long>> segProjectOrganizationIds = segmentateUtil.doCut(projectOrganizationIds, 999);

        IPage<ProjectAssignmentVo> pagination;
        if (StringUtils.isEmpty(lastName) && StringUtils.isEmpty(userName) && StringUtils.isEmpty(mobile) && StringUtils.isEmpty(employeeNum)) {
            pagination = projectAssignmentMapper.selectPaginationContainsProjectOrganizationChildren(page, projectId, segProjectOrganizationIds);
        } else {
            List<Long> personIds = personnelRemoteApiService.getPersonIdsByLastNameAndUserNameAndEmployeeNumAndMobile(lastName, userName, employeeNum, mobile);
            List<List<Long>> segPersonIds = segmentateUtil.doCut(personIds, 999);

            pagination = projectAssignmentMapper.selectPaginationWithPersonIdsContainsProjectOrganizationChildren(page, projectId, segProjectOrganizationIds, segPersonIds);
        }

        // 装配信息
        assembleRemoteInfo(pagination.getRecords());

        return pagination;
    }

    @Override
    public ProjectAssignmentForMobile getProjectAssignmentContainsChildren(Long projectId, Long projectOrganizationId, String lastName, String userName, String employeeNum, String mobile) {
        ProjectAssignmentForMobile projectAssignmentForMobile = new ProjectAssignmentForMobile();

        if (projectOrganizationId == null) {
            throw LogicException.raise(CustomError.PROJECT_ORGANIZATION_ID_MISS);
        }

        List<Long> projectOrganizationIds = organizationRemoteApiService.getProjectOrganizationChildrenOrgIdList(projectOrganizationId);
        List<List<Long>> segProjectOrganizationIds = segmentateUtil.doCut(projectOrganizationIds, 999);

        List<ProjectAssignmentVo> projectAssignmentVos;
        if (StringUtils.isEmpty(lastName) && StringUtils.isEmpty(userName) && StringUtils.isEmpty(mobile) && StringUtils.isEmpty(employeeNum)) {
            projectAssignmentVos = projectAssignmentMapper.selectContainsProjectOrganizationChildren(projectId, segProjectOrganizationIds);
        } else {
            List<Long> personIds = personnelRemoteApiService.getPersonIdsByLastNameAndUserNameAndEmployeeNumAndMobile(lastName, userName, employeeNum, mobile);
            List<List<Long>> segPersonIds = segmentateUtil.doCut(personIds, 999);

            projectAssignmentVos = projectAssignmentMapper.selectWithPersonIdsContainsProjectOrganizationChildren(projectId, segProjectOrganizationIds, segPersonIds);
        }

        // 装配信息
        assembleRemoteInfo(projectAssignmentVos);
        projectAssignmentForMobile.setProjectAssignments(projectAssignmentVos);
        projectAssignmentForMobile.setDingNames(inmallRemoteApiService.getUsersByProjectId(projectId));
        return projectAssignmentForMobile;
    }

    @Override
    public ProjectAssignmentForMobile getProjectAssignment(Long projectId, Long projectOrganizationId, String lastName, String userName, String employeeNum, String mobile) {
        ProjectAssignmentForMobile projectAssignmentForMobile = new ProjectAssignmentForMobile();

        List<ProjectAssignmentVo> projectAssignmentVos;
        if (StringUtils.isEmpty(lastName) && StringUtils.isEmpty(userName) && StringUtils.isEmpty(mobile) && StringUtils.isEmpty(employeeNum)) {
            projectAssignmentVos = projectAssignmentMapper.selectByProjectIdAndProjectOrganizationId(projectId, projectOrganizationId);
        } else {
            List<Long> personIds = personnelRemoteApiService.getPersonIdsByLastNameAndUserNameAndEmployeeNumAndMobile(lastName, userName, employeeNum, mobile);
            List<List<Long>> segPersonIds = segmentateUtil.doCut(personIds, 999);
            projectAssignmentVos = projectAssignmentMapper.selectWithPersonIds(projectId, projectOrganizationId, segPersonIds);
        }

        assembleRemoteInfo(projectAssignmentVos);
        projectAssignmentForMobile.setProjectAssignments(projectAssignmentVos);
        projectAssignmentForMobile.setDingNames(inmallRemoteApiService.getUsersByProjectId(projectId));
        return projectAssignmentForMobile;
    }

    @Override
    public List<Long> getPersonIdsByProjectId(Long projectId) {
        return projectAssignmentRepository.selectPersonIdsByProjectId(projectId);
    }

    @Override
    public List<ProjectAssignment> getByPersonIds(List<Long> personIds) {
        return projectAssignmentRepository.selectProjectAssignmentsByPersonIds(personIds);
    }

    @Override
    public List<Long> getPersonIdsByProjectIdNoToken(Long projectId) {
        return projectAssignmentRepository.selectPersonIdsByProjectIdNoToken(projectId);
    }

    @Override
    public Map<Long, String> getProjectNamesByPersonIds(List<Long> personIds) {
        Map<Long, String> maps = new HashMap<>();
        for (Long personId : personIds) {
            List<Long> projectIds = projectAssignmentMapper.selectProjectIdsByPersonId(personId);
            String projectName = "";
            for (Long projectId : projectIds) {
                ProjectBasic projectBasic = projectBasicRepository.selectByProjectId(projectId);
                if (projectBasic != null) {
                    projectName += projectBasic.getProjectName() + "；";
                }
            }

            if (!"".equals(projectName)) {
                projectName = projectName.substring(0, projectName.length() - 1);
            }
            maps.put(personId, projectName);
        }

        return maps;
    }

    @Override
    public List<ProjectAssignmentVo> getProjectAssignmentsByPersonId(Long personId) {
        List<ProjectAssignment> projectAssignments = projectAssignmentRepository.selectProjectAssignmentsByPersonId(personId);
        List<ProjectAssignmentVo> views = dozerUtil.convertor(projectAssignments, ProjectAssignmentVo.class);

        for (ProjectAssignmentVo view : views) {
            // 项目组织信息
            if (view.getProjectOrganizationId() != null) {
                ProjectOrganizationResponse projectOrganization = organizationRemoteApiService.getProjectOrganizationView(view.getProjectOrganizationId());
                if (projectOrganization != null) {
                    view.setProjectOrganizationShortName(projectOrganization.getShortName())
                            .setProjectOrganizationName(projectOrganization.getFullName())
                            .setProjectOrganizationCode(projectOrganization.getOrganizationCode())
                            .setProjectOrganizationType(projectOrganization.getType())
                            .setProjectOrganizationTypeMeaning(projectOrganization.getTypeMeaning());
                }
            }

            // 项目信息
            if (view.getProjectId() != null) {
                ProjectBasicVo projectBasicVo = projectBasicQueryService.getProjectBasicView(view.getProjectId());
                if (projectBasicVo != null) {
                    view.setProjectCode(projectBasicVo.getProjectCode())
                            .setProjectName(projectBasicVo.getProjectName())
                            .setProjectShortName(projectBasicVo.getProjectShortName());
                }
            }
        }

        return views;
    }

    @Override
    public List<ProjectAssignment> getProjectAssignmentsByPersonIdNoToken(Long personId) {
        return projectAssignmentRepository.selectProjectAssignmentsByPersonIdSkipSql(personId);
    }

    @Override
    public List<Long> getDistinctProjectIdsByPersonId(Long personId) {
        List<ProjectAssignment> assignments = projectAssignmentRepository.selectProjectAssignmentsByPersonId(personId);
        List<Long> projectIds = assignments.stream().map(ProjectAssignment::getProjectId).sorted(Comparator.comparing(Long::longValue).reversed()).distinct().collect(Collectors.toList());
        return projectIds;
    }

    @Override
    public List<ProjectAssignment> getProjectAssignmentList(ProjectAssignmentListQueryCommand projectAssignmentListQueryCommand) {
        ProjectAssignmentQuery projectAssignmentQuery = dozerUtil.convertor(projectAssignmentListQueryCommand, ProjectAssignmentQuery.class);
        return projectAssignmentRepository.getProjectAssignmentList(projectAssignmentQuery);
    }

    @Override
    public List<ProjectAssignment> getProjectAssignmentListWithoutToken(ProjectAssignmentListQueryCommand projectAssignmentListQueryCommand) {
        ProjectAssignmentQuery projectAssignmentQuery = dozerUtil.convertor(projectAssignmentListQueryCommand, ProjectAssignmentQuery.class);
        return projectAssignmentRepository.getProjectAssignmentListWithoutToken(projectAssignmentQuery);
    }
}
